﻿using BUGCOME.Infrastructure;
using BUGCOME.Infrastructure.Model;
using BUGCOME.Model.Auth;
using BUGCOME.ServiceCore.Services;
using BUGCOME.ServiceCore.Services.IServices;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace BUGCOME.ServiceCore.Filters
{
    /// <summary>
    /// API授权判断
    /// </summary>
    public class ActionPermissionFilter : ActionFilterAttribute//, IAsyncActionFilter
    {
        private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 权限字符串，例如 admin:user:view
        /// </summary>
        public string Permission { get; set; } = string.Empty;
        /// <summary>
        /// 角色字符串，例如 common,admin
        /// </summary>
        public string RolePermi { get; set; } = string.Empty;
        private bool HasPermi { get; set; }
        public ActionPermissionFilter() { }
        public ActionPermissionFilter(string permission)
        {
            Permission = permission;
            HasPermi = !string.IsNullOrEmpty(Permission);
        }

        /// <summary>
        /// 执行Action前校验是否有权限访问
        /// </summary>
        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            TokenModel info = JwtUtil.GetLoginUser(context.HttpContext);

            if (info != null && info.UserId > 0)
            {
                long userId = info.UserId;
                List<string> perms = CacheService.GetUserPerms(GlobalConstant.UserPermKEY + userId);
                List<string> rolePerms = info.RoleIds ?? new List<string>();

                // 从缓存或服务获取权限
                if (perms == null)
                {
                    var sysPermissionService = App.GetService<IPermissionService>();
                    perms = await sysPermissionService.GetMenuPermissionAsync(new UserBase { Id = userId });
                    CacheService.SetUserPerms(GlobalConstant.UserPermKEY + userId, perms);
                }

                // 权限判断逻辑
                if (perms?.Exists(f => f.Equals(GlobalConstant.AdminPerm)) == true)
                {
                    HasPermi = true;
                }
                else if (rolePerms.Exists(f => f.Equals(GlobalConstant.AdminRole)))
                {
                    HasPermi = true;
                }
                else if (!string.IsNullOrEmpty(Permission))
                {
                    HasPermi = perms?.Exists(f => string.Equals(f, Permission, StringComparison.OrdinalIgnoreCase)) == true;
                }

                // 角色权限补充判断
                if (!HasPermi && !string.IsNullOrEmpty(RolePermi))
                {
                    HasPermi = info.RoleIds?.Contains(RolePermi) == true;
                }

                // 演示模式权限限制
                bool isDemoMode = AppSettings.GetAppConfig("DemoMode", false);
                var url = context.HttpContext.Request.Path;
                string[] denyPerms = { "update", "add", "remove", "edit", "delete", "import", "run", "start", "stop", "clear", "send", "export", "upload", "common", "gencode", "reset", "forceLogout", "batchLogout" };

                if (isDemoMode && !string.IsNullOrEmpty(Permission) && denyPerms.Any(f => Permission.IndexOf(f, StringComparison.OrdinalIgnoreCase) >= 0))
                {
                    context.Result = new JsonResult(new ApiResult((int)ResultCode.FORBIDDEN, "演示模式 , 不允许操作"));
                    return;
                }

                // 无权限处理
                if (!HasPermi && !string.Equals(Permission, "common", StringComparison.Ordinal))
                {
                    var apiResult = new ApiResult((int)ResultCode.FORBIDDEN, "你当前没有权限访问,请联系管理员", url);
                    apiResult.Put("permi", Permission);

                    context.HttpContext.Response.StatusCode = 403;
                    context.Result = new JsonResult(apiResult)
                    {
                        ContentType = "application/json"
                    };
                    return;
                }
            }

            // 继续执行后续逻辑
            await next();
        }
    }
}
